/*
 * $RCSfile: BackupJob.java,v $
 * $Revision: 1.1 $
 * $Date: 2012-11-01 $
 *
 * Copyright (C) 2008 Skin, Inc. All rights reserved.
 *
 * This software is the proprietary information of Skin, Inc.
 * Use is subject to license terms.
 */
package com.skin.webcat.job;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Connection;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.skin.j2ee.util.ParameterParser;
import com.skin.j2ee.util.Parameters;
import com.skin.webcat.database.Table;
import com.skin.webcat.database.handler.TableHandler;
import com.skin.webcat.exchange.DataExport;
import com.skin.webcat.exchange.SqlDataExport;
import com.skin.webcat.util.IO;
import com.skin.webcat.util.Jdbc;
import com.skin.webcat.util.Webcat;

/**
 * <p>Title: BackupJob</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2006</p>
 * @author xuesong.net
 * @version 1.0
 */
public class BackupJob {
    private static final Logger logger = LoggerFactory.getLogger(BackupJob.class);

    /**
     * 定时备份
     * @param properties
     */
    public void execute(String properties) {
        if(logger.isInfoEnabled()) {
            logger.info("backup: {}", properties);
        }

        Parameters parameters = ParameterParser.parse(properties);
        String connectionName = parameters.getTrimString("connectionName");
        String database = parameters.getTrimString("database");
        String[] tableNameList = parameters.getParameterValues("tableName");

        if(database.length() < 1) {
            return;
        }

        Connection connection = null;

        try {
            connection = Webcat.getConnection(connectionName, database);
            TableHandler tableHandler = new TableHandler(connection);
            List<Table> tableList = tableHandler.getTableList(null, null, "%", new String[]{"TABLE"}, false);
            
            if(tableNameList == null || tableNameList.length < 1) {
                tableNameList = this.getTableNameList(tableList);
            }

            String webInfo = this.getWebInfo();
            String token = UUID.randomUUID().toString();
            this.backup(connectionName, database, tableNameList, new File(webInfo + "/backup"), token);
        }
        catch(Exception e) {
            logger.error(e.getMessage(), e);
        }
        finally {
            Jdbc.close(connection);
        }
    }

    /**
     * @param tableList
     * @return List<String>
     */
    private String[] getTableNameList(List<Table> tableList) {
        List<String> result = new ArrayList<String>();

        if(tableList != null) {
            for(Table table : tableList) {
                result.add(table.getTableName());
            }
        }

        String[] array = new String[result.size()];
        result.toArray(array);
        return array;
    }

    /**
     * @param dataExport
     * @param tableNameList
     */
    protected void backup(String name, String database, String[] tableNameList, File dir, String token) {
        Connection connection = null;
        OutputStream outputStream = null;
        ZipOutputStream zipOutputStream = null;

        boolean success = false;
        File file = new File(dir, token + ".temp");
        DataExport dataExport = new SqlDataExport();

        try  {
            connection = Webcat.getConnection(name, database);
            dataExport.setConnection(connection);
            outputStream = new FileOutputStream(file);
            zipOutputStream = new ZipOutputStream(outputStream);

            for(String table : tableNameList) {
                ZipEntry entry = new ZipEntry(table + ".sql");
                zipOutputStream.putNextEntry(entry);
                dataExport.execute(table, zipOutputStream, "utf-8");
            }

            zipOutputStream.finish();
            zipOutputStream.flush();
            outputStream.flush();
            success = true;
        }
        catch(Exception e) {
            logger.error(e.getMessage(), e);
        }
        finally {
            IO.close(zipOutputStream);
            IO.close(outputStream);
            Jdbc.close(connection);
        }

        if(success) {
            logger.info("backup complete !");

            try {
                File target = this.getTarget(dir, ".zip");
                file.renameTo(target);
            }
            catch(IOException e) {
                logger.error(e.getMessage(), e);
            }
        }
        else {
            logger.info("backup failed !");
            file.deleteOnExit();
        }
    }

    /**
     * @return String
     */
    private String getWebInfo() {
        try {
            String path = BackupJob.class.getClassLoader().getResource("").toURI().getPath();

            if(path == null) {
                return null;
            }

            path = path.replace('\\', '/');
            int k = path.indexOf("/WEB-INF/");

            if(k > -1) {
                return path.substring(0, k + 8);
            }
        }
        catch (Exception e) {
            logger.warn(e.getMessage(), e);
        }
        return null;
    }

    /**
     * @param parent
     * @param extension
     * @return File
     * @throws IOException
     */
    private File getTarget(File parent, String extension) throws IOException {
        File target = null;
        long timeMillis = System.currentTimeMillis();
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");

        while(true) {
            timeMillis += 1000;
            Date currentTime = new Date(timeMillis);
            target = new File(parent, dateFormat.format(currentTime) + extension);

            if(target.exists() == false) {
                break;
            }
        }
        return target;
    }
}
